package lv.ante.dziesmas.raster;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.media.jai.JAI;
import javax.media.jai.ROI;
import javax.media.jai.ROIShape;
import javax.media.jai.RenderedOp;

import com.sun.media.jai.codec.ImageCodec;
import com.sun.media.jai.codec.ImageEncoder;
import com.sun.media.jai.codec.PNGEncodeParam;

public class CropPng {

	static {
		System.setProperty("com.sun.media.jai.disableMediaLib", "true");
	}

	public static int TOP_LEFT_X = 0;
	public static int TOP_LEFT_Y = 0;
	public static int WIDTH = 835;
	public static int HEIGHT = 1130;

	public static void main(String[] args) throws IOException {
		if (args.length < 1) {
			System.err.println("Usage: CropPng <filename>");
			System.exit(0);
		}
		ParameterBlock pb = new ParameterBlock();
		pb.add(args[0] + ".png");
		RenderedOp inputRO = JAI.create("fileload", pb);

		RenderedOp outputRO = cropBottom(inputRO);

		int[] dim = getDimensions(outputRO);
		for (int i = 0; i < dim.length; i++) {
			System.out.println("dim[i] = " + dim[i]);
		}

		RenderedOp autoCroppedRO = crop(inputRO, dim[2], dim[0], dim[3]
				- dim[2], dim[1] - dim[0]);

		OutputStream os = new FileOutputStream(args[0] + ".new.png");
		PNGEncodeParam param = new PNGEncodeParam.Gray();
		ImageEncoder enc = ImageCodec.createImageEncoder("PNG", os, param);
		enc.encode(autoCroppedRO);
		os.close();

	}

	public static int[] getDimensions(RenderedImage ri) {
		// top side
		int a1 = 0;
		int b1 = HEIGHT;
		int c1 = 0;
		while (b1 - a1 > 1) {
			// System.out.println("TOP a = " + a1 + ", b = " + b1);
			c1 = (b1 + a1) / 2;
			int result = measureExtremes(ri, 0, 0, 835, c1);
			if (result == 255) {
				a1 = c1;
			} else {
				b1 = c1;
			}
		}
		// bottom side
		int a2 = 0;
		int b2 = HEIGHT;
		int c2 = 0;
		while (b2 - a2 > 1) {
			// System.out.println("BOTTOM a = " + a2 + ", b = " + b2);
			c2 = (b2 + a2) / 2;
			int result = measureExtremes(ri, 0, HEIGHT - c2, 835, c2);
			if (result == 255) {
				a2 = c2;
			} else {
				b2 = c2;
			}
		}

		// left side
		int a3 = 0;
		int b3 = WIDTH;
		int c3 = 0;
		while (b3 - a3 > 1) {
			// System.out.println("LEFT a = " + a3 + ", b = " + b3);
			c3 = (b3 + a3) / 2;
			int result = measureExtremes(ri, 0, 0, c3, HEIGHT);
			if (result == 255) {
				a3 = c3;
			} else {
				b3 = c3;
			}
		}

		// right side
		int a4 = 0;
		int b4 = WIDTH;
		int c4 = 0;
		while (b4 - a4 > 1) {
			// System.out.println("RIGHT a = " + a4 + ", b = " + b4);
			c4 = (b4 + a4) / 2;
			int result = measureExtremes(ri, WIDTH - c4, 0, c4, HEIGHT);
			if (result == 255) {
				a4 = c4;
			} else {
				b4 = c4;
			}
		}
		return new int[] { a1, HEIGHT - a2, a3, WIDTH - a4 };

	}

	public static int measureExtremes(RenderedImage ri, int x, int y,
			int width, int height) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(ri); // The source image
		// pb.add(null); // The region of the image to scan
		ROIShape roi = new ROIShape(new Rectangle(x, y, width, height));
		pb.add(roi);
		pb.add(1); // The horizontal sampling rate
		pb.add(1); // The vertical sampling rate

		// Retrieve both the maximum and minimum pixel value
		double[][] extrema = new double[][] { { -1, -1, -1 }, { -1, -1, -1 } };
		try {
			// Perform the extrema operation on the source image
			RenderedOp op = JAI.create("extrema", pb);
			extrema = (double[][]) op.getProperty("extrema");
		} catch (Exception e) {
		}
		// System.out.println("x = " + x + ", y = " + y + ", width = " + width +
		// ", height = " + height + ", extr = " + extrema[0][0]);
		return (int) extrema[0][0];

	}

	public static RenderedOp crop(RenderedImage ri, int x, int y, int width,
			int height) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(ri);
		pb.add((float) x);
		pb.add((float) y);
		pb.add((float) width);
		pb.add((float) height);
		RenderedOp outputRO = JAI.create("Crop", pb);
		return outputRO;
	}

	public static RenderedOp cropBottom(RenderedImage ri) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(ri);
		pb.add((float) TOP_LEFT_X);
		pb.add((float) TOP_LEFT_Y);
		pb.add((float) WIDTH);
		pb.add((float) HEIGHT);
		RenderedOp outputRO = JAI.create("Crop", pb);
		return outputRO;
	}

}
